package com.peak.spring.boot.builder.repository;

import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.util.Assert;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.peak.spring.boot.api.repository.FilterParam;
import com.peak.spring.boot.api.repository.FilterParam.Operator;
import com.peak.spring.boot.tools.Converts;
import com.peak.spring.boot.tools.Emptys;
import com.peak.spring.boot.tools.Servlets;

public class FilterParamBuilder {

	private List<FilterParam> filterParams = Lists.newArrayList();
	
	private PageRequest pageRequest;

	public static FilterParamBuilder create() {
		FilterParamBuilder builder = new FilterParamBuilder();
		return builder;
	}
	
	public List<FilterParam> build() {
		return this.filterParams;
	}
	
	public List<FilterParam> filters() {
		return this.filterParams;
	}

	public PageRequest pageRequest() {
		return this.pageRequest;
	}

	public FilterParamBuilder eq(String fieldName, Object value) {
		filterParams.add(new FilterParam(fieldName, Operator.EQ, value));
		return this;
	}
	
	public FilterParamBuilder neq(String fieldName, Object value) {
		filterParams.add(new FilterParam(fieldName, Operator.NEQ, value));
		return this;
	}

	public FilterParamBuilder like(String fieldName, Object value) {
		filterParams.add(new FilterParam(fieldName, Operator.LIKE, value));
		return this;
	}

	public FilterParamBuilder llike(String fieldName, Object value) {
		filterParams.add(new FilterParam(fieldName, Operator.LLIKE, value));
		return this;
	}

	public FilterParamBuilder rlike(String fieldName, Object value) {
		filterParams.add(new FilterParam(fieldName, Operator.RLIKE, value));
		return this;
	}

	public FilterParamBuilder gt(String fieldName, Object value) {
		filterParams.add(new FilterParam(fieldName, Operator.GT, value));
		return this;
	}

	public FilterParamBuilder lt(String fieldName, Object value) {
		filterParams.add(new FilterParam(fieldName, Operator.LT, value));
		return this;
	}

	public FilterParamBuilder gte(String fieldName, Object value) {
		filterParams.add(new FilterParam(fieldName, Operator.GTE, value));
		return this;
	}

	public FilterParamBuilder lte(String fieldName, Object value) {
		filterParams.add(new FilterParam(fieldName, Operator.LTE, value));
		return this;
	}

	public FilterParamBuilder in(String fieldName, Object value) {
		filterParams.add(new FilterParam(fieldName, Operator.IN, value));
		return this;
	}

	public FilterParamBuilder notin(String fieldName, Object value) {
		filterParams.add(new FilterParam(fieldName, Operator.NOTIN, value));
		return this;
	}

	public FilterParamBuilder between(String fieldName, Object value) {
		filterParams.add(new FilterParam(fieldName, Operator.BETWEEN, value));
		return this;
	}

	public FilterParamBuilder isnull(String fieldName) {
		filterParams.add(new FilterParam(fieldName, Operator.ISNULL, "null"));
		return this;
	}

	public FilterParamBuilder notnull(String fieldName) {
		filterParams.add(new FilterParam(fieldName, Operator.NOTNULL, "notnull"));
		return this;
	}

	public FilterParamBuilder empty(String fieldName) {
		filterParams.add(new FilterParam(fieldName, Operator.EMPTY, "empty"));
		return this;
	}

	public FilterParamBuilder notempty(String fieldName) {
		filterParams.add(new FilterParam(fieldName, Operator.NOTEMPTY, "notempty"));
		return this;
	}

	/**
	 * value等于空的都不要，如果本来就是无value的，强行传入一个字符串
	 * 
	 * @param filterMap
	 * @return
	 */
	public FilterParamBuilder parseMap(Map<String, Object> filterMap) {
		if (Emptys.isNotEmpty(filterMap)) {
			for (Entry<String, Object> entry : filterMap.entrySet()) {
				// 过滤value为空的
				Object value = entry.getValue();
				String key = entry.getKey();
				this.add(key, value);
			}
		}
		return this;
	}

	/**
	 * 添加一个条件
	 * 
	 * @param key 格式举例: eq_name
	 * @param value 数组格式应转为：String,String
	 * @return
	 */
	public FilterParamBuilder add(String key, Object value) {
		if (Emptys.isNotEmpty(Converts.toString(value))) {
			String fieldName = StringUtils.substringAfterLast(key, "_");
			Operator op = Operator.valueOf(StringUtils.substringBeforeLast(key, "_"));
			filterParams.add(new FilterParam(fieldName, op, value));
		}
		return this;
	}

	/**
	 * 从request中取查询参数，前缀必须是filter_，否则不会使用
	 * 
	 * @param request
	 * @return
	 */
	public FilterParamBuilder parseRequest(HttpServletRequest request) {
		Assert.notNull(request, "Request must not be null");
		Enumeration<String> paramNames = request.getParameterNames();
		Map<String, Object> pageMap = Maps.newHashMap();
		String prefix = Servlets.PARAM_PREFIX;
		String pagePrefix = Servlets.PAGE_PREFIX;
		while (paramNames != null && paramNames.hasMoreElements()) {
			String paramName = paramNames.nextElement();
			if (paramName.startsWith(prefix)) {
				String value = null;
				String unprefixed = paramName.substring(prefix.length());
				String[] values = request.getParameterValues(paramName);
				if (Emptys.isNotEmpty(values)) {
					if (values.length > 1) {
						value = Joiner.on(",").skipNulls().join(values);
					} else {
						value = values[0];
						if (Emptys.isEmpty(value)) {
							value = null;
						}
					}
					this.add(unprefixed, StringUtils.trim(value));
				}
			} else if (paramName.startsWith(pagePrefix)) {
				String unprefixed = paramName.substring(pagePrefix.length());
				pageMap.put(unprefixed, request.getParameter(paramName));
			}
		}
		// 把payload里面的参数也取出来
		Map<String, Object> map = Servlets.getParamFromPayload(request);
		if (Emptys.isNotEmpty(map)) {
			for (Entry<String, Object> entry : map.entrySet()) {
				String paramName = entry.getKey();
				if ("".equals(prefix) || paramName.startsWith(prefix)) {
					String unprefixed = paramName.substring(prefix.length());
					this.add(unprefixed, entry.getValue());
				} else if (paramName.startsWith(pagePrefix)) {
					String unprefixed = paramName.substring(pagePrefix.length());
					pageMap.put(unprefixed, entry.getValue());
				}
			}
		}
		// payload里面的数据只能取一次，好恶心
		if (Emptys.isNotEmpty(pageMap)) {
			this.pageRequest = Servlets.getPages(pageMap);
		}
		return this;
	}

}
